<template>
  <el-row class="node-analysis">
    <el-row class="analyse-input-block">
      <el-row class="_title-h1">
        Customized Analysis of your Open Source Repository
      </el-row>
      <el-row class="form-block">
        <el-col :span="18" style="padding-right: 20px">
          <el-input v-model="url_input" placeholder="请输入GitHub上的开源仓库地址"></el-input>
        </el-col>
        <el-col :span="4">
          <el-select v-model="manager_select" placeholder="请选择项目包管理器">
            <el-option label="Maven" value="1"></el-option>
          </el-select>
        </el-col>
        <el-col :span="2" style="text-align: right">
          <el-button type="primary" icon="el-icon-aim" @click="analyse"> 分析</el-button>
        </el-col>
      </el-row>
    </el-row>
    <el-row v-show="is_analysis" class="analyse-output-block" v-loading="is_analysis_loading">
      <el-row class="_title-h2">
        项目依赖项 ({{ project_dependencies.length }})
      </el-row>
      <el-table
          class="output-table"
          :data="project_dependencies"
          stripe
          style="width: 100%"
      >
        <el-table-column
          prop="id"
          label="软件包ID"
          width="400">
          <template v-slot="scope">
             <el-tag class="_hover" @click="to_pkg_detail(scope.row.id)">
              {{ scope.row.id }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column
          prop="cve"
          label="漏洞项"
          width="500">
          <template v-slot="scope">
            <el-row v-if="scope.row.cve.length>0">
              <el-tag v-for="(cve, index) in scope.row.cve" :key="index" class="cve-tag _hover" @click="to_cve_detail(scope.row.cve[index].id)">
                {{ cve.id }}
              </el-tag>
            </el-row>
            <el-row v-else class="_green">未发现漏洞</el-row>
          </template>
        </el-table-column>
        <el-table-column
          label="操作">
          <template v-slot="scope">
            <span class="_blue _hover" @click="to_pkg_detail(scope.row.id)">查看详情</span>
            <span class="_red _hover" @click="to_pkg_vuln_analyse(scope.row.id)" style="margin-left: 20px">漏洞分析</span>
          </template>
        </el-table-column>
      </el-table>
      <el-row class="_title-h2">
        项目依赖图谱
      </el-row>
      <el-row class="graph-block" ref="viz_maven" id="viz_maven" v-show="manager_confirmed==='1'"></el-row>
      <el-row class="graph-opt">
        <el-col class="graph-hint" :span="4">
          <el-row class="hint-text">* 悬停以显示节点信息</el-row>
        </el-col>
        <el-col class="graph-hint" :span="4">
          <el-row class="hint-text">* 点击以显示扩展信息</el-row>
        </el-col>
        <el-col class="graph-btn-container" :span="16">
          <el-button @click="hide_ex_info" class="graph-btn">隐藏扩展信息</el-button>
        </el-col>
      </el-row>
    </el-row>
    <el-row v-show="!is_analysis" class="recommend-block">
      <el-row class="_title-h1">
        Popular Software Packages Included
      </el-row>
      <el-row class="logo-block">
      <el-col :span="3" class="logo-image">
        <el-image
            class="_hover logo-img"
            :src="require('../../assets/maven_logo.png')"
            fit="fit"
            @click="show_maven_lists"
        >
        </el-image>
      </el-col>
      <el-col class="logo-info" :class="(ecosystem_to_show==='maven') ? '_wide':'_thin'">
        <el-row class="info-container">
          Website: <span class="_url" @click="to_url(homepage_maven)">{{ homepage_maven }}</span>
        </el-row>
        <el-row class="info-container">
          Total Packages: {{ version_num_maven }}
        </el-row>
      </el-col>
      <el-col :span="3" class="logo-image">
        <el-image
            class="_hover logo-img"
            :src="require('../../assets/pypi_logo.png')"
            fit="fit"
            @click="show_pypi_lists"
        >
        </el-image>
      </el-col>
      <el-col class="logo-info" :class="(ecosystem_to_show==='pypi') ? '_wide':'_thin'">
        <el-row class="info-container">
          Website: <span class="_url" @click="to_url(homepage_pypi)">{{ homepage_pypi }}</span>
        </el-row>
        <el-row class="info-container">
          Total Packages: {{ version_num_pypi }}
        </el-row>
      </el-col>
      <el-col :span="3" class="logo-image">
        <el-image
            class="_hover logo-img"
            :src="require('../../assets/euler_logo.png')"
            fit="fit"
            @click="show_euler_lists"
        >
        </el-image>
      </el-col>
      <el-col class="logo-info" :class="(ecosystem_to_show==='euler') ? '_wide':'_thin'">
        <el-row class="info-container">
          Website: <span class="_url" @click="to_url(homepage_euler)">{{ homepage_euler }}</span>
        </el-row>
        <el-row class="info-container">
          Total Packages: {{ version_num_euler }}
        </el-row>
      </el-col>
      <el-col :span="3" class="logo-image">
        <el-image
            class="_hover logo-img"
            :src="require('../../assets/ubuntu_logo.png')"
            fit="fit"
            @click="show_ubuntu_lists"
        >
        </el-image>
      </el-col>
      <el-col class="logo-info" :class="(ecosystem_to_show==='ubuntu') ? '_wide':'_thin'">
        <el-row class="info-container">
          Website: <span class="_url" @click="to_url(homepage_ubuntu)">{{ homepage_ubuntu }}</span>
        </el-row>
        <el-row class="info-container">
          Total Packages: {{ version_num_ubuntu }}
        </el-row>
      </el-col>
      <el-col :span="3" class="logo-image">
        <el-image
            class="_hover logo-img"
            :src="require('../../assets/harmony_logo.png')"
            fit="fit"
            @click="show_harmony_lists"
        >
        </el-image>
      </el-col>
      <el-col class="logo-info" :class="(ecosystem_to_show==='harmony') ? '_wide':'_thin'">
        <el-row class="info-container">
          Website: <span class="_url" @click="to_url(homepage_harmony)">{{ homepage_harmony }}</span>
        </el-row>
        <el-row class="info-container">
          Total Packages: {{ version_num_harmony }}
        </el-row>
      </el-col>
    </el-row>
      <el-row class="list-block">
      <el-col class="list-container" :span="8">
        <el-row class="list-title">
          Critical Packages
        </el-row>
        <el-row class="pkg-list">
          <el-scrollbar style="height: 100%">
            <el-row v-for="(pkg, index) in critical_pkg_list" class="list-item" :key="index">
              <el-row class="item-name" @click.native="to_pkg_detail(pkg.name)">{{ pkg.name }}</el-row>
              <el-row class="item-score">Critical score: <span style="color: #529b2e">{{ Math.round(pkg.score) }}</span></el-row>
            </el-row>
          </el-scrollbar>
        </el-row>
      </el-col>
      <el-col class="list-container" :span="8">
        <el-row class="list-title">
          High PageRank Packages
        </el-row>
        <el-row class="pkg-list">
          <el-scrollbar style="height: 100%">
            <el-row v-for="(pkg, index) in pagerank_pkg_list" class="list-item" :key="index">
              <el-row class="item-name" @click.native="to_pkg_detail(pkg.name)">{{ pkg.name }}</el-row>
              <el-row class="item-score">PageRank: <span style="color: #529b2e">{{ Math.round(pkg.pagerank) }}</span></el-row>
              <el-row class="item-info">{{ pkg.info }}</el-row>
            </el-row>
          </el-scrollbar>
        </el-row>
      </el-col>
      <el-col class="list-container" :span="8">
        <el-row class="list-title">
          Most Depended upon Packages
        </el-row>
        <el-row class="pkg-list">
          <el-scrollbar style="height: 100%">
            <el-row v-for="(pkg, index) in depe_pkg_list" class="list-item" :key="index">
              <el-row class="item-name" @click.native="to_pkg_detail(pkg.name)">{{ pkg.name }}</el-row>
              <el-row class="item-score">Dependent packages: <span style="color: #529b2e">{{ pkg.depen_cnt }}</span></el-row>
              <el-row class="item-info">{{ pkg.info }}</el-row>
            </el-row>
          </el-scrollbar>
        </el-row>
      </el-col>
    </el-row>
    </el-row>
  </el-row>
</template>

<script>
import axios from "axios";
import NeoVis from 'neovis.js/dist/neovis.js';
import {f} from "core-js/internals/new-promise-capability";

export default {
  name: "NodeAnalysis",
  data() {
    return {
      // analyse_block
      url_input: "https://github.com/junit-team/junit4.git",
      manager_select: "1",
      manager_confirmed: null,
      default_cypher: "",
      is_analysis_loading: false,
      is_analysis: false,
      project_dependencies: [],
      neovis_labels: {
        Package: {
          caption: 'ID',  // 节点显示的文字对应内容key
          size: "1",  // 用作节点大小的属性名。默认为1
          font: { size: 12, color: '#2c3e50' },  // 字体设置
        },
        Project: {
          caption: 'name',
          size: "1",
          font: { size: 12, color: '#2c3e50' },  // 字体设置
        },
        Vulnerability: {
          caption: 'name',
          size: "1",
          font: { size: 12, color: '#2c3e50' },  // 字体设置
        },
        Developer: {
          caption: 'name',
          size: "1",
          font: { size: 12, color: '#2c3e50' },  // 字体设置
        },
        Repository: {
          caption: 'URL',
          size: "1",
          font: { size: 12, color: '#2c3e50' },  // 字体设置
        },
      },    // neovis的label样式配置
      neovis_relationships: {
        depends_on_project: {
          thickness: "1",
          caption: true,
          font: { size: 12, color: '#2c3e50'},
        },
        depends_on_pkg: {
          thickness: "1",
          caption: true,
          font: { size: 12, color: '#2c3e50'},
        },
        buildrequire_pkg: {
          thickness: "1",
          caption: true,
          font: { size: 12, color: '#2c3e50'},
        },
        include_vul: {
          thickness: "1",
          caption: true,
          font: { size: 12, color: '#2c3e50'},
        },
        affect_pkg: {
          thickness: "1",
          caption: true,
          font: { size: 12, color: '#2c3e50'},
        },
        vul_exploit: {
          thickness: "1",
          caption: true,
          font: { size: 12, color: '#2c3e50'},
        },
        part_of_project: {
          thickness: "1",
          caption: true,
          font: { size: 12, color: '#2c3e50'},
        },
        develop: {
          thickness: "1",
          caption: true,
          font: { size: 12, color: '#2c3e50'},
        },
        include_developer: {
          thickness: "1",
          caption: true,
          font: { size: 12, color: '#2c3e50'},
        },
        store_at: {
          thickness: "1",
          caption: true,
          font: { size: 12, color: '#2c3e50'},
        },
        include_pkg: {
          thickness: "1",
          caption: true,
          font: { size: 12, color: '#2c3e50'},
        },
        commit_update_repo: {
          thickness: "1",
          caption: true,
          font: { size: 12, color: '#2c3e50'},
        },
      },    // neovis的relationship样式配置
      // recommend_block
      ecosystem_to_show: "maven",
      homepage_maven: "https://maven.org",
      homepage_pypi: "https://pypi.org/",
      homepage_euler: "https://www.openeuler.org/",
      homepage_ubuntu: "https://www.ubuntu.org.cn/",
      homepage_harmony: "http://www.openharmony.cn/",
      version_num_maven: 0,
      version_num_pypi: 0,
      version_num_euler: 0,
      version_num_ubuntu: 0,
      version_num_harmony: 0,
      depe_pkg_list: [],
      pagerank_pkg_list: [],
      critical_pkg_list: [],
      maven_lists: [],
      pypi_lists: [],
      euler_lists: [],
      ubuntu_lists: [],
      harmony_lists: [],
    }
  },
  methods: {
    // analyse_block
    analyse: function () {
      // pre
      this.is_analysis = true;
      this.manager_confirmed = this.manager_select;
      this.is_analysis_loading = true;
      // judge
      let repo_url = this.url_input.replace(/(^\s*)|(\s*$)/g, "");
      let manager = this.manager_select
      if (repo_url === "") {
        this.$message.error('请输入目标分析仓库地址')
        return
      }
      if (manager === "") {
        this.$message.error('请选择目标仓库的包管理器')
        return
      }
      // axios
      axios({
        method: "get",
        params: { repo_url: repo_url, manager: manager },
        url: "http://localhost:8000/search/analyse_repo"
      }).then(res => {
        if (res.status !== 200) {
          this.$message.error('分析项目仓库出错')
        } else {
          this.project_dependencies = res.data.data
          // 图谱更新
          this.viz_maven.clearNetwork()
          let statement = ""
          for (let i = 0; i < this.project_dependencies.length; i++) {
            let cypher = 'match p=(n)-[r*0..1]->() where n.ID= "' + this.project_dependencies[i].id + '" return p limit 100'
            if ( i > 0 ) {
              statement += " UNION "
            }
            statement += cypher
          }
          console.log(statement)
          this.default_cypher = statement
          this.viz_maven.updateWithCypher(statement)
        }
        this.is_analysis_loading = false
      })
    },
    to_pkg: function (pkg) {
      let platform = "maven"
      if (this.manager_confirmed === "1") {
        platform = "maven"
      }
      this.$emit("change_tag", { to: 2, pkg: pkg, platform: platform})
    },
    config_maven_graph: function() {
      let config = {
        container_id: 'viz_maven', // dom元素id
        server_url: 'bolt://211.71.15.39:8687',
        server_user: 'neo4j',
        server_password: 'maven',
        // 节点样式配置
        labels: this.neovis_labels,
        // 关系样式配置
        relationships: this.neovis_relationships,
        // 其他配置
        arrows: true,  // 关系线段是否显示箭头
        hierarchical: false, // 节点显示方式(是否启用分层布局)
        hierarchical_sort_method: 'directed',
        encrypted: 'ENCRYPTION_OFF',
        trust: 'TRUST_ALL_CERTIFICATES',
        initial_cypher: ""
      }
      this.viz_maven = new NeoVis(config)
      this.viz_maven.render()
      // 注册点击事件
      this.viz_maven.registerOnEvent('clickNode', this.node_click)
    },
    node_click: function (node) {
      this.viz_maven._network.off('click')
      const statement ='match p = (n)-[r]->() where id(n)= ' + node.nodeId + ' return p limit 100'
      this.viz_maven.updateWithCypher(statement)
    },
    hide_ex_info: function () {
      this.viz_maven.clearNetwork()
      this.viz_maven.updateWithCypher(this.default_cypher)
    },
    // recommend_block
    to_url: function (url) {
      window.open(url)
    },
    to_pkg_detail: function (pkg_id) {
      this.$emit("change_tag", { to: 2, pkg: pkg_id, platform: this.ecosystem_to_show })
    },
    to_pkg_vuln_analyse: function (pkg_id) {
      this.$emit("change_tag", { to: 3, pkg: pkg_id, platform: this.ecosystem_to_show })
    },
    show_maven_lists: function () {
      this.ecosystem_to_show = "maven"
      this.critical_pkg_list = this.maven_lists[0]
      this.pagerank_pkg_list = this.maven_lists[1]
      this.depe_pkg_list = this.maven_lists[2]
    },
    show_pypi_lists: function () {
      this.ecosystem_to_show = "pypi"
      this.critical_pkg_list = this.pypi_lists[0]
      this.pagerank_pkg_list = this.pypi_lists[1]
      this.depe_pkg_list = this.pypi_lists[2]
    },
    show_euler_lists: function () {
      this.ecosystem_to_show = "euler"
      this.critical_pkg_list = this.euler_lists[0]
      this.pagerank_pkg_list = this.euler_lists[1]
      this.depe_pkg_list = this.euler_lists[2]
    },
    show_ubuntu_lists: function () {
      this.ecosystem_to_show = "ubuntu"
      this.critical_pkg_list = this.ubuntu_lists[0]
      this.pagerank_pkg_list = this.ubuntu_lists[1]
      this.depe_pkg_list = this.ubuntu_lists[2]
    },
    show_harmony_lists: function () {
      this.ecosystem_to_show = "harmony"
      this.critical_pkg_list = this.harmony_lists[0]
      this.pagerank_pkg_list = this.harmony_lists[1]
      this.depe_pkg_list = this.harmony_lists[2]
    },
  },
  computed: {

  },
  mounted() {
    // 版本数目初始化
    axios({
      method: "get",
      params: { },
      url: "http://localhost:8000/search/pkg_num"
    }).then(res => {
      if (res.status !== 200) {
        this.$message.error('获取包版本数时出现未知错误')
      } else {
        this.version_num_maven = res.data.data["maven"]
        this.version_num_pypi = res.data.data["pypi"]
        this.version_num_euler = res.data.data["euler"]
        this.version_num_ubuntu = res.data.data["ubuntu"]
        this.version_num_harmony = res.data.data["harmony"]
      }
    })
    // 列表初始化
    axios({
      method: "get",
      params: { },
      url: "http://localhost:8000/search/maven_pkg_lists"
    }).then(res => {
      if (res.status !== 200) {
        this.$message.error('获取Maven包列表时出现未知错误')
      } else {
        this.maven_lists = res.data.data
        this.critical_pkg_list = this.maven_lists[0]
        this.pagerank_pkg_list = this.maven_lists[1]
        this.depe_pkg_list = this.maven_lists[2]
      }
    })
    axios({
      method: "get",
      params: { },
      url: "http://localhost:8000/search/euler_pkg_lists"
    }).then(res => {
      if (res.status !== 200) {
        this.$message.error('获取Euler包列表时出现未知错误')
      } else {
        this.euler_lists = res.data.data
      }
    })
    axios({
      method: "get",
      params: { },
      url: "http://localhost:8000/search/pypi_pkg_lists"
    }).then(res => {
      if (res.status !== 200) {
        this.$message.error('获取Pypi包列表时出现未知错误')
      } else {
        this.pypi_lists = res.data.data
      }
    })
    axios({
      method: "get",
      params: { },
      url: "http://localhost:8000/search/ubuntu_pkg_lists"
    }).then(res => {
      if (res.status !== 200) {
        this.$message.error('获取Pypi包列表时出现未知错误')
      } else {
        this.ubuntu_lists = res.data.data
      }
    })
    axios({
      method: "get",
      params: { },
      url: "http://localhost:8000/search/harmony_pkg_lists"
    }).then(res => {
      if (res.status !== 200) {
        this.$message.error('获取OpenHarmony包列表时出现未知错误')
      } else {
        this.harmony_lists = res.data.data
      }
    })
    // 图谱初始化
    this.config_maven_graph()
  },
}
</script>

<style scoped>
.form-block {
  padding: 10px 0;
}

.graph-block {
  margin-top: 15px;
  margin-left: 10px;
  width: 99.3%;
  height: 750px;
  border-left: #2c3e50 4px solid;
  border-right: rgba(44, 62, 80, 0.05) 1px solid;
  background-color: rgba(44, 62, 80, 0.05);
}
.graph-opt {
  text-align: left;
  margin-top: 10px;
  margin-left: 10px;
}
.hint-text {
  color: #909399;
  font-size: 14px;
  margin-top: 5px;
}
.graph-btn-container {
  text-align: right;
}
.graph-btn {
  height: 32px;
  line-height: 32px;
  width: 120px;
  padding: 0;
}
.cve-tag {
  background-color: #fff2f5;
  border-color: #ffdbe2;
  color: crimson;
  margin-right: 10px;
}

.recommend-block {
  margin-top: 20px;
}

.logo-block {
  height: 120px;
  text-align: left;
  padding: 10px 0;
  margin: 10px 0;
}
.logo-image {
  text-align: center;
}
.logo-img {
  height: 100px;
}
.logo-info {
  font-size: 15px;
  overflow: hidden;
  white-space: nowrap;
  transition: 0.5s;
}
.info-container {
  padding-top: 20px;
}

.list-block {
  margin-top: 0;
}
.list-container {
  text-align: left;
  padding: 10px;
}
.list-title {
  font-size: 20px;
}
.pkg-list {
  margin-top: 10px;
  height: 460px;
  width: 350px;
  overflow-y: auto;
}
.pkg-list >>> .el-scrollbar__wrap {
  overflow-x: hidden;
}
.pkg-list >>> .el-scrollbar__bar.is-horizontal {
  display: none;
}
.list-item {
  border-left: #2c3e50 2px solid;
  margin-top: 20px;
  padding-left: 10px;
  padding-right: 10px;
}
.item-name {
  color: #395cc5;
  font-size: 15px;
  font-weight: bold;
}
.item-name:hover {
  cursor: pointer;
  color: #021f7c;
  text-decoration:underline
}
.item-score {
  margin-top: 8px;
  font-size: 14px;
  color: grey;
}
.item-info {
  margin-top: 8px;
  font-size: 14px;
  line-height: 20px;
  text-align: justify;
}

._url {
  color: #5192ff;
}
._url:hover {
  color: #2373ff;
  cursor: pointer;
}
._hover:hover {
  cursor: pointer;
}
._wide {
  width: 400px;
}
._thin {
  width: 0;
}
._title-h1 {
  margin: 10px 0;
  font-size: 26px;
  text-align: left;
  color: #1d2641;
}
._title-h2 {
  margin-top: 20px;
  margin-bottom: 10px;
  font-size: 18px;
  text-align: left;
}
._blue {
  color: #0e90ff !important;
}
._red {
  color: crimson !important;
}
._green {
  color: #52ad26 !important;
}
</style>